package org.rpc.proxy.jdk;

import org.rpc.common.RpcInvocation;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.TimeoutException;

import static org.rpc.common.cache.CommonClientCache.RESP_MAP;
import static org.rpc.common.cache.CommonClientCache.SEND_QUEUE;

public class JDKInvocationHandler implements InvocationHandler {
    private final static Object OBJECT = new Object();

    private Class<?> clazz;

    public JDKInvocationHandler(Class<?> clazz) {
        this.clazz = clazz;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcInvocation rpcInvocation = new RpcInvocation();
        // 具体发送给服务端的数据包装
        rpcInvocation.setArgs(args);
        rpcInvocation.setTargetMethod(method.getName());
        rpcInvocation.setTargetServiceName(clazz.getName());
        rpcInvocation.setUuid(UUID.randomUUID().toString());
        // 默认给一个空的返回，主要是生成这个uuid，让发送和接收关联上
        RESP_MAP.put(rpcInvocation.getUuid(), OBJECT);
        // 添加到发送队列中，让线程异步发送，实现异步并发
        SEND_QUEUE.add(rpcInvocation);
        long beginTime = System.currentTimeMillis();
        // 控制一下超时时间，在3秒内，会不断的获取当前的uuid是否有返回值
        while (System.currentTimeMillis() - beginTime < 3 * 1000) {
            Object object = RESP_MAP.get(rpcInvocation.getUuid());
            // 因为在一开始，我们给RESP_MAP中的对应的uuid的值是object，如果一旦发送到服务端，且服务端处理完成之后，返回的是RpcInvocation对象，故用RpcInvocation表示成功发送
            if (object instanceof RpcInvocation) {
                // 返回发送结果
                return ((RpcInvocation) object).getResponse();
            }
        }
        throw new TimeoutException("超时异常");
    }
}
